/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * NewJFrame.java
 *
 * Created on 01-Apr-2009, 17:18:48
 */

package edu.napier.soc.xfdm.uci;

import edu.napier.soc.xfdm.model.EntityType;
import edu.napier.soc.xfdm.uci.EntityTypeView.RelationshipModel;
import edu.napier.soc.xfdm.uci.EntityTypeView.RelationshipModel.Cardinality;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.JToolBar.Separator;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * @author Thomas
 */
public class DatabaseView extends javax.swing.JFrame {

	private List<EntityTypeView> panels = new LinkedList<EntityTypeView>();
	private boolean relationships = true;
	private boolean supertypes = true;

	/**
	 * Creates new form NewJFrame
	 */
	public DatabaseView() {
		initComponents();
	}

	private final Random r = new Random();

	public DatabaseView(List<EntityType> entityTypes, JFrame owner) {
		super(owner.getTitle() + " - Visual Viewer");
		setIconImage(owner.getIconImage());
		contentPane.setLayout(null);
		contentPane.setPreferredSize(new Dimension(800, 550));
		add(contentPane, BorderLayout.CENTER);
		initComponents();

		for (EntityType e : entityTypes) {
			EntityTypeView view = new EntityTypeView(e);
			addEntityTypeView(view);
		}
		setLocationRelativeTo(owner);
		contentPane.addComponentListener(new ComponentAdapter() {

			@Override
			public void componentResized(ComponentEvent e) {
				for (Component c : contentPane.getComponents()) {
					c.setLocation(checkInBounds(c, c.getLocation()));
				}
				repaint();
			}
		});
	}

	public void addEntityTypeView(EntityTypeView view) {
		panels.add(view);
		Dimension viewSize = view.getPreferredSize();
		Dimension paneSize = contentPane.getPreferredSize();
		view.addMouseListener(ml);
		view.addMouseMotionListener(ml);
		view.setSize(view.getPreferredSize());
		view.setLocation(
				r.nextInt((int) (paneSize.getWidth() - viewSize.getWidth())),
				r.nextInt((int) (paneSize.getHeight() - viewSize.getHeight())));
		contentPane.add(view);
	}

	private void drawRelationship(Graphics2D g2, RelationshipModel rel,
	                              EntityTypeView from, EntityTypeView to) {
		int pX = from.getX() + (from.getWidth() / 2);
		int pY = from.getY() + (from.getHeight() / 2);
		int p1X = to.getX() + (to.getWidth() / 2);
		int p1Y = to.getY() + (to.getHeight() / 2);
		Line2D line = new Line2D.Float(pX, pY, p1X, p1Y);
		g2.setStroke(new BasicStroke(2));
		Color old = g2.getColor();
		if (rel.getCardinality() == Cardinality.SUPERTYPE) {
			if (!supertypes) {
				return;
			}
			g2.setColor(Color.RED);
			//g2.drawLine(pX, pY, p1X, p1Y);
			g2.draw(line);
			g2.setColor(old);
			return;
		}
		if (!relationships) {
			return;
		}
//			g2.drawLine(pX, pY, p1X, p1Y);
		g2.draw(line);
		String label = rel.getFunction().getName() + " "
				+ rel.getCardinality().getName();

		int difX = Math.abs(pX - p1X) / 2;
		int difY = Math.abs(pY - p1Y) / 2;
		int startX = Math.min(pX, p1X);
		int startY = Math.min(pY, p1Y);
		int labelW = g2.getFontMetrics().stringWidth(label);
		int labelH = g2.getFontMetrics().getHeight();
		int offsetX = startX + difX - (labelW / 2);
		int offsetY = startY + difY - (labelH / 2);
		g2.setColor(this.getBackground());
		g2.fillRect(offsetX - 2, offsetY, labelW + 4, labelH + 2);
		g2.setColor(old);
		g2.drawString(label, offsetX, offsetY + labelH);
	}

	private void drawEntityTypeView(Graphics2D g2, EntityTypeView e) {
		for (RelationshipModel rel : e.getRelationships()) {
			EntityTypeView to = null;

			for (EntityTypeView current : panels) {
				if (current.getEntityType() == rel.getRelationshipTo()) {
					to = current;
					break;
				}
			}

			if (to != null) {
				drawRelationship(g2, rel, e, to);
			}
		}
	}

	private void drawDatabaseView(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
				RenderingHints.VALUE_STROKE_NORMALIZE);

		for (EntityTypeView view : panels) {
			drawEntityTypeView(g2, view);
		}
	}

	/**
	 * This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
	// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
	private void initComponents() {

		toolBar = new JToolBar();
		inheritanceButton = new JToggleButton();
		relationshipsButton = new JToggleButton();
		seperator = new Separator();
		imageButton = new JButton();

		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

		toolBar.setRollover(true);

		inheritanceButton.setIcon(new ImageIcon(getClass().getResource(
				"/edu/napier/soc/xfdm/resources/inher.png"))); // NOI18N
		inheritanceButton.setToolTipText("Show Inheritance");
		inheritanceButton.setFocusable(false);
		inheritanceButton.setHorizontalTextPosition(SwingConstants.CENTER);
		inheritanceButton.setVerticalTextPosition(SwingConstants.BOTTOM);
		inheritanceButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				inheritanceButtonActionPerformed(evt);
			}
		});
		toolBar.add(inheritanceButton);

		relationshipsButton.setIcon(new ImageIcon(getClass().getResource(
				"/edu/napier/soc/xfdm/resources/rels.png"))); // NOI18N
		relationshipsButton.setToolTipText("Show Relationships");
		relationshipsButton.setFocusable(false);
		relationshipsButton.setHorizontalTextPosition(SwingConstants.CENTER);
		relationshipsButton.setVerticalTextPosition(SwingConstants.BOTTOM);
		relationshipsButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				relationshipsButtonActionPerformed(evt);
			}
		});
		toolBar.add(relationshipsButton);
		toolBar.add(seperator);

		imageButton.setIcon(new ImageIcon(getClass().getResource(
				"/edu/napier/soc/xfdm/resources/image.png"))); // NOI18N
		imageButton.setToolTipText("Save to Image");
		imageButton.setFocusable(false);
		imageButton.setHorizontalTextPosition(SwingConstants.CENTER);
		imageButton.setVerticalTextPosition(SwingConstants.BOTTOM);
		imageButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				imageButtonActionPerformed(evt);
			}
		});
		toolBar.add(imageButton);

		getContentPane().add(toolBar, BorderLayout.PAGE_START);

		pack();
	}// </editor-fold>//GEN-END:initComponents

	private void inheritanceButtonActionPerformed(
			ActionEvent evt) {//GEN-FIRST:event_inheritanceButtonActionPerformed
		supertypes = !supertypes;
		repaint();
	}//GEN-LAST:event_inheritanceButtonActionPerformed

	private void relationshipsButtonActionPerformed(
			ActionEvent evt) {//GEN-FIRST:event_relationshipsButtonActionPerformed
		relationships = !relationships;
		repaint();
	}//GEN-LAST:event_relationshipsButtonActionPerformed

	private void imageButtonActionPerformed(
			ActionEvent evt) {//GEN-FIRST:event_imageButtonActionPerformed
		if (contentPane.getHeight() < 0 || contentPane.getWidth() < 0) {
			JOptionPane.showMessageDialog(this,
					"Display area height and width must be greater than 0",
					"Save Image Error", JOptionPane.WARNING_MESSAGE);
			return;
		}
		File f = MainGUI.saveFile(this,
				new FileNameExtensionFilter("PNG File (*.png)", "png"));

		if (f == null) {
			return;
		}

		BufferedImage out = new BufferedImage(contentPane.getWidth(),
				contentPane.getHeight(), BufferedImage.TYPE_INT_RGB);
		contentPane.paintAll(out.getGraphics());
		try {
			if (!f.getName().toLowerCase().endsWith(".png")) {
				f = new File(f.getAbsolutePath() + ".png");
			}
			ImageIO.write(out, "png", f);
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}//GEN-LAST:event_imageButtonActionPerformed

	public Point checkInBounds(Component c, Point p) {
		if (p.getX() < 0) {
			p.setLocation(0, p.getY());
		} else if (p.getX() + c.getWidth() > contentPane.getWidth()) {
			p.setLocation(contentPane.getWidth() - c.getWidth(), p.getY());
		}
		if (p.getY() < 0) {
			p.setLocation(p.getX(), 0);
		} else if (p.getY() + c.getHeight() > contentPane.getHeight()) {
			p.setLocation(p.getX(), contentPane.getHeight() - c.getHeight());
		}
		return p;
	}

	private JPanel contentPane = new JPanel() {

		@Override
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			drawDatabaseView(g);
		}
	};

	private MouseAdapter ml = new MouseAdapter() {
		private JComponent dragging;
		private int x;
		private int y;

		@Override
		public void mousePressed(MouseEvent e) {
			dragging = (JComponent) e.getSource();
			x = e.getX();
			y = e.getY();
		}

		@Override
		public void mouseDragged(MouseEvent e) {
			Point p = SwingUtilities.convertPoint(dragging, e.getX() - x,
					e.getY() - y, contentPane);

			dragging.setLocation(checkInBounds(dragging, p));
			repaint();
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			dragging = null;
		}
	};

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private JButton imageButton;
	private JToggleButton inheritanceButton;
	private JToggleButton relationshipsButton;
	private Separator seperator;
	private JToolBar toolBar;
	// End of variables declaration//GEN-END:variables

}
